home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_489 / mkbmap / mkbmap.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  28KB  |  959 lines

  1. /* Amiga bitmapped font builder.  File "mkbmap.c".
  2.  * (C) Adrian Aylward 1991
  3.  *
  4.  * You may freely copy, use, and modify this file.
  5.  *
  6.  * This program prints builds an Amiga format bitmapped screen font file
  7.  * from the corresponding PostScript font, using post.library. It is totally
  8.  * Amiga specific.
  9.  *
  10.  * The program was tested using Lattice C V5.05.  It has various Lattice
  11.  * dependencies.
  12.  *
  13.  * This is version 1.0.
  14.  */
  15.  
  16. # include <dos.h>
  17. # include <exec/exec.h>
  18. # include <libraries/diskfont.h>
  19. # include <proto/diskfont.h>
  20. # include <proto/dos.h>
  21. # include <proto/exec.h>
  22. # include <string.h>
  23. # include <stdarg.h>
  24. # include <stdio.h>
  25.  
  26. # include "postlib.h"
  27.  
  28. # undef  POSTVERNO
  29. # define POSTVERNO 15  /* We need post.library version 1.5+ */
  30.  
  31. /* The following definitions appear to be missing from the Lattice headers */
  32.  
  33. # ifdef LATTICE
  34. extern struct FontContentsHeader *NewFontContents(BPTR lock, char *name);
  35. extern void DisposeFontContents(struct FontContentsHeader *fc);
  36.  
  37. # pragma libcall DiskfontBase NewFontContents     2a   9802 ; d0 = (a0, a1)
  38. # pragma libcall DiskfontBase DisposeFontContents 30    901 ;      (a1)
  39. # endif
  40.  
  41. /* Assembler routines */
  42.  
  43. extern void insertftrap(void);
  44. extern void deleteftrap(void);
  45.  
  46. /* Object module hunks */
  47.  
  48. # define Hunk_Header  0x3F3
  49. # define Hunk_Code    0x3E9
  50. # define Hunk_Reloc32 0x3EC
  51. # define Hunk_End     0x3F2
  52.  
  53. # define MOVFFD0RTS   0x70FF4E75
  54.  
  55. /* External data (initialised to zero) */
  56.  
  57. char *argbmapfile, *argfontname, *argpointsizes;
  58. char *argstartupfile, *argencodingfile;
  59. int optfontencoding, optnew;
  60. int optmonospaced, optbold, optitalic, opttrace;
  61. int optden, optxden, optyden, optbaseline, optwidth;
  62. int pointc, pointn, pointv[100];
  63.  
  64. int retcode;
  65.  
  66. int arec;
  67.  
  68. struct library *PSbase;
  69. struct PSparm parm;
  70.  
  71. APTR functab[10];
  72.  
  73. int ftrapset;
  74.  
  75. int pointsize;
  76. char namebuf[100 + 5];
  77. char psstring[200];
  78. int pserror;
  79.  
  80. int lochar, hichar;
  81. int baseline, nomwidth, nomcount;
  82.  
  83. int llx[256], lly[256], urx[256], ury[256];
  84.  
  85. int cposx, cposy;
  86.  
  87. void *fontmem;
  88. int baselen;
  89. int maxfontlen, maxcharlen, maxmodulo, maxwidth; 
  90. int actfontlen, actcharlen, actmodulo, actwidth; 
  91. int hunklen, hunknum, *hunkptr;
  92.  
  93. BPTR fdlock, cdlock, newfh;
  94.  
  95. struct FontContentsHeader *fcheader;
  96.  
  97. struct DiskFontHeader *dfheader;
  98.  
  99. char *chardata;
  100. short *charloc, *charspace, *charkern;
  101.  
  102. /* Routines */
  103.  
  104. extern int strtoint(char **sp, int *ip);
  105. extern char *buildfnumname(char *nbuf, char *name, int num);
  106. extern char *buildfdirname(char *nbuf, char *name, int type);
  107. extern void pstrace(char *format, ...);
  108. extern void pssintf(char *format, ...);
  109. extern void __saveds setbbox(int ch, int lx, int ly, int rx, int uy);
  110. extern void __saveds setcpos(int cpx, int cpy);
  111.  
  112. /* Main program */
  113.  
  114. void main(int argc, char **argv)
  115. {   char *s, *t;
  116.     int *ip, i, l, ch;
  117.     int y1, y2, z1, z2, zz, ww;
  118.  
  119.     /* Parse arguments.  No workbench startup */
  120.  
  121.     optxden = optyden = 75;
  122.     optbaseline = optwidth = -1;
  123.     lochar = 32;
  124.     hichar = 255;
  125.  
  126.     if (argc == 0) goto tidyexit;
  127.     argv++;
  128.     argc--;
  129.     if (argc == 0 || (argc == 1 && strcmp(*argv, "?") == 0)) goto query;
  130.  
  131.     while (argc)
  132.     {   s = *argv;
  133.         if (*s != '-') break;
  134.         argv++;
  135.         argc--;
  136.         if (strcmp(s, "--") == 0) break;
  137.         s++;
  138.         for (;;)
  139.         {   ch = *s++;
  140.             if (ch == 0) break;
  141.             switch (ch)
  142.             {   case 'S': case 's':
  143.                     if (argc == 0) goto badargs;
  144.                     argstartupfile = *argv++;
  145.                     argc--;
  146.  
  147.                 case 'E': case 'e':
  148.                     if (argc == 0) goto badargs;
  149.                     argencodingfile = *argv++;
  150.                     argc--;
  151.  
  152.                 case 'F': case 'f':
  153.                     optfontencoding = 1;
  154.                     continue;
  155.  
  156.                 case 'N': case 'n':
  157.                     optnew = 1;
  158.                     continue;
  159.  
  160.                 case 'D': case 'd':
  161.                     ip = &optden;
  162.                     break;
  163.  
  164.                 case 'X': case 'x':
  165.                     ip = &optxden;
  166.                     break;
  167.  
  168.                 case 'Y': case 'y':
  169.                     ip = &optyden;
  170.                     break;
  171.  
  172.                 case 'Z': case 'z':
  173.                     ip = &optbaseline;
  174.                     break;
  175.  
  176.                 case 'L': case 'l':
  177.                     ip = &lochar;
  178.                     break;
  179.  
  180.                 case 'W': case 'w':
  181.                     ip = &optwidth;
  182.                     break;
  183.  
  184.                 case 'H': case 'h':
  185.                     ip = &hichar;
  186.                     break;
  187.  
  188.                 case 'M': case 'm':
  189.                     optmonospaced = 1;
  190.                     continue;
  191.  
  192.                 case 'B': case 'b':
  193.                     optbold = 1;
  194.                     continue;
  195.  
  196.                 case 'I': case 'i':
  197.                     optitalic = 1;
  198.                     continue;
  199.  
  200.                 case 'T': case 't':
  201.                     opttrace = 1;
  202.                     continue;
  203.  
  204.                 default:
  205.                     fprintf(stderr, "mkbmap: unknown option \"-%c\"", ch);
  206.                     goto badusage;
  207.             }
  208.             if (!strtoint(&s, ip)) goto badargs;
  209.             if (ip == &optden) optxden = optyden = optden;
  210.         }
  211.  
  212.         if (*s == '-' && *(s + 1) == 0) break;
  213.     }
  214.  
  215.     if (lochar > hichar || hichar > 255)
  216.     {   fprintf(stderr, "mkbmap: LoChar/HiChar out of range "
  217.                                 "(0 <= Lo <= Hi <= 255)\n");
  218.         goto errorexit;
  219.     }
  220.  
  221.     if (argc != 1 && argc != 3) goto badargs;
  222.     argbmapfile = argv[0];
  223.     if (argc == 3)
  224.     {   argfontname = argv[1];
  225.         argpointsizes = argv[2];
  226.  
  227.         s = argpointsizes;
  228.         while (*s)
  229.         {   i = 0;
  230.             for (;;)
  231.             {   ch = *s;
  232.                 if (ch == 0) break;
  233.                 s++;
  234.                 if (ch == ',') break;
  235.                 if (ch >= '0' && ch <= '9')
  236.                     i = i * 10 + (ch - '0');
  237.                 else
  238.                     goto badargs;
  239.             }
  240.             if (i != 0)
  241.             {   if (i < 5 || i > 500)
  242.                 {   fprintf(stderr, "mkbmap: point size %d out of range "
  243.                                             "(5 - 500)\n", pointsize);
  244.                     goto errorexit;
  245.                 }
  246.                 if (pointc == 100) goto badargs;
  247.                 pointv[pointc++] = i;
  248.             }
  249.         }
  250.     }
  251.  
  252.     if (pointc == 0) goto newfont;
  253.  
  254.     if (argencodingfile == NULL) argencodingfile = "PSFonts:encoding.ps";
  255.     if (argstartupfile  == NULL) argstartupfile  = "PSFonts:init.ps";
  256.  
  257.     /* Initialise the PostScript library */
  258.  
  259.     pstrace("%% Opening PostScript library\n");
  260.     PSbase = OpenLibrary("post.library", POSTVERNO);
  261.     if (PSbase == NULL)
  262.     {   fprintf(stderr, "mkbmap: can't open post.library (V15+)\n");
  263.         goto errorexit;
  264.     }
  265.  
  266.     pstrace("%% Initialising PostScript activation\n");
  267.     parm.page.buf[0] = namebuf;
  268.     parm.page.len = 100;
  269.     parm.page.depth = 1;
  270.     parm.page.xoff = 0;
  271.     parm.page.yoff = 0;
  272.     parm.page.xbytes = 10;
  273.     parm.page.xsize = 80;
  274.     parm.page.ysize = 10;
  275.     parm.page.ybase = 0;
  276.     parm.page.yheight = 10;
  277.     parm.page.xden = 72;
  278.     parm.page.yden = 72;
  279.     parm.page.ydir = -1;
  280.     parm.memvlen = 20000;
  281.     parm.memflen = 10000;
  282.     parm.memllen = defmemllen;
  283.     parm.memhlen = minmemhlen;
  284.     parm.infh = Input();
  285.     parm.outfh = Output();
  286.     parm.errfh = Output();
  287.     parm.funcmax = 2;
  288.     functab[0] = (APTR) setbbox;
  289.     functab[1] = (APTR) setcpos;
  290.     parm.functab = functab;
  291.     insertftrap();
  292.     ftrapset = 1;
  293.     arec = PScreateact(&parm);
  294.     if (arec == 0)
  295.     {   fprintf(stderr, "mkbmap: post.library can't get memory\n");
  296.         goto errorexit;
  297.     }
  298.     if ((unsigned) arec <= errmax)
  299.     {   pserror = arec;
  300.         arec = 0;
  301.         goto pserror;
  302.     }
  303.  
  304.     /* Load the startup file */
  305.  
  306.     pstrace("%% Loading startup file\n");
  307.     pssintf("(%.100s) run clear\n", argstartupfile);
  308.  
  309.     /* Load the encoding file */
  310.  
  311.     if (optfontencoding == 0)
  312.     {   pstrace("% Loading encoding file\n");
  313.         pssintf("/encoding StandardEncoding 256 array copy def\n");
  314.         pssintf("[ (%.100s) run ] aload length 2 idiv\n", argencodingfile);
  315.         pssintf("{ encoding 3 1 roll put } repeat\n");
  316.     }
  317.  
  318.  
  319.     /* Load the font.  Make sure we don't get a substitute */
  320.  
  321.     pstrace("%% Loading font\n");
  322.     pssintf("/fontname /%.100s def\n", argfontname);
  323.     pssintf("fontname findfont pop\n");
  324.     pssintf("/font fontname .findfont def\n");
  325.  
  326.     /* Encode the font */
  327.  
  328.     pstrace("%% Encoding font\n");
  329.     pssintf("/newfont font maxlength dict def\n");
  330.     pssintf("font\n"
  331.             "{ exch dup /FID ne "
  332.             "{ exch newfont 3 1 roll put } { pop pop } ifelse }\n"
  333.             "forall\n");
  334.     if (optfontencoding == 0)
  335.            pssintf("newfont /Encoding encoding put\n");
  336.     pssintf("/_%.100s newfont definefont pop\n", argfontname);
  337.     if (pserror != 0) goto pserror;
  338.  
  339.     pstrace("%% LoChar = %d; HiChar = %d\n", lochar, hichar);
  340.  
  341.     /* Determine the bounding boxes for all the characters */
  342.  
  343.     pstrace("%% Generating bounding boxes\n");
  344.     pssintf("/cstr 1 string def\n");
  345.     pssintf("newfont 1000 scalefont setfont\n");
  346.     pssintf("%d 1 %d\n"
  347.             "{ /i exch def cstr 0 i put null i\n"
  348.             "  0 0 moveto cstr false charpath pathbbox newpath\n"
  349.             "  4 { round cvi 4 1 roll } repeat\n"
  350.             "  5 0 callextfunc\n"
  351.             "} for\n", lochar, hichar);
  352.     if (pserror != 0) goto pserror;
  353.  
  354.     /* Position the baseline, if we have not set it explicitly */
  355.  
  356.     if (optbaseline == -1)
  357.     {
  358.         /* This is what we have room for */
  359.  
  360.         zz = (1000 * 72) / optyden;
  361.  
  362.         /* Calculate the lower and upper limits of the whole character set */
  363.  
  364.         z1 = z2 = 0;
  365.         for (i = 0; i <= 255 ; i++)
  366.         {   if (lly[i] < z1) z1 = lly[i];
  367.             if (ury[i] > z2) z2 = ury[i];
  368.         }
  369.         if (z2 == z1)
  370.         {   fprintf(stderr, "mkbmap: all characters in the font are null\n");
  371.             goto errorexit;
  372.         }
  373.  
  374.         /* If we have room for everything, or the font has a non-standard
  375.          * character set, set the baseline in proportion to the relative
  376.          * sizes of the ascenders and descenders */
  377.  
  378.         optbaseline = (1000 * (-z1) + (z2 - z1) / 2) / (z2 - z1);
  379.  
  380.         /* Otherwise, for fonts with standard character sets, calculate the
  381.          * limits of the alphabet.  If we have room for that then leave just
  382.          * enough room for the descenders, or else set the baseline
  383.          * proportionately */
  384.  
  385.         if (z2 - z1 > zz && optfontencoding == 0)
  386.         {   y1 = y2 = 0;
  387.             for (i = 'A'; i <= 'Z' ; i++)
  388.             {   if (lly[i] < y1) y1 = lly[i];
  389.                 if (ury[i] > y2) y2 = ury[i];
  390.             }
  391.             for (i = 'a'; i <= 'z' ; i++)
  392.             {   if (lly[i] < y1) y1 = lly[i];
  393.                 if (ury[i] > y2) y2 = ury[i];
  394.             }
  395.             if (y2 - y1 <= zz)
  396.                 optbaseline = (1000 * (-y1) + zz / 2) / zz;
  397.             else
  398.                 optbaseline = (1000 * (-y1) + (y2 - y1) / 2) / (y2 - y1);
  399.         }
  400.         pstrace("%% Baseline set at %d/1000 of the pixel height\n",
  401.                 optbaseline);
  402.     }
  403.  
  404.     /* Validate the font file name and create the font subdirectory */
  405.  
  406.     if (buildfdirname(namebuf, argbmapfile, 0) == NULL)
  407.     {   fprintf(stderr, "mkbmap: bmap file has no directory path\n");
  408.         goto errorexit;
  409.     }
  410.     if (optnew)
  411.     {   fdlock = CreateDir(namebuf);
  412.         if (fdlock)
  413.         {   UnLock(fdlock);
  414.             fdlock = 0;
  415.         }
  416.     }
  417.  
  418.     /* Loop through all the point sizes */
  419.  
  420.     for (pointn = 0; pointn < pointc; pointn++)
  421.     {   if (SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C) goto broken;
  422.  
  423.         pointsize = pointv[pointn];
  424.         pstrace("%% Point size %d\n", pointsize);
  425.         baseline = (pointsize * optbaseline + 500) / 1000;
  426.         if (baseline < 0) baseline = 0;
  427.         if (baseline > pointsize - 1) baseline = pointsize - 1;
  428.  
  429.  
  430.         /* Build the bitmapped font in memory.  Estimate the maximum
  431.          * possible width of the bitmap from the total widths of the
  432.          * bounding boxes, allowing 2 extra pixels per character for
  433.          * rounding and stem alignment.  Calculate the mamimum font
  434.          * length, allocate the memory, and initialise the headers */
  435.  
  436.         baselen = 4 + sizeof (struct DiskFontHeader) +
  437.                       8 * (hichar - lochar + 2);
  438.  
  439.         maxwidth = 0;
  440.         for (ch = lochar; ch <= hichar ; ch++)
  441.             maxwidth +=
  442.                 ((urx[ch] - llx[ch]) * pointsize * optxden) / 72000 + 2;
  443.         maxmodulo = ((maxwidth + 15) >> 3) & ~1;
  444.         maxcharlen = maxmodulo * pointsize;
  445.         maxfontlen = baselen + maxcharlen + 2 + 76;
  446.  
  447.         fontmem = AllocMem(maxfontlen, MEMF_PUBLIC|MEMF_CLEAR);
  448.         if (fontmem == NULL)
  449.         {   fprintf(stderr, "mkbmap: can't get font memory\n");
  450.             goto errorexit;
  451.         }
  452.  
  453.         hunkptr   = fontmem;
  454.         dfheader  = (void *) &hunkptr[9];
  455.         charloc   = (void *) &dfheader[1];
  456.         charspace = (void *) &charloc[(hichar - lochar + 2) * 2];
  457.         charkern  = (void *) &charspace[hichar - lochar + 2];
  458.         chardata  = (void *) &charkern[hichar - lochar + 2];
  459.  
  460.         /* Set up the bitmap to render the characters */
  461.  
  462.         pstrace("%% Rendering bitmaps\n");
  463.         parm.page.buf[0] = (char *) chardata;
  464.         parm.page.len = maxcharlen;
  465.         parm.page.depth = 1;
  466.         parm.page.xoff = 0;
  467.         parm.page.yoff = 0;
  468.         parm.page.xbytes = maxmodulo;
  469.         parm.page.xsize = maxwidth;
  470.         parm.page.ysize = pointsize;
  471.         parm.page.ybase = 0;
  472.         parm.page.yheight = pointsize;
  473.         PSsetdevice(arec, &parm.page);
  474.  
  475.         pssintf("initmatrix\n");
  476.         pssintf("/xscale %d %d mul 72 div def\n", pointsize, optxden);
  477.         pssintf("/yscale %d %d mul 72 div def\n", pointsize, optyden);
  478.         pssintf("newfont [ xscale 0 0 yscale 0 0 ] makefont setfont\n");
  479.  
  480.         actwidth = 0;
  481.         nomwidth = 0;
  482.         nomcount = 0;
  483.  
  484.         /* Loop to render each character.  We estimate the bounds of the
  485.          * characters conservatively (hinting any shift them a little) and
  486.          * trim the bitmap if possible.  We clip on the left, so any part
  487.          * of the character projecting to the left is truncated, and does
  488.          * not overwrite the previous one.  We erase the character cell so
  489.          * it does not matter if the clipping of the right of the previous
  490.          * character was not complete.  We render the portiona above and
  491.          * below the baseline separately, so they can be indepently scaled
  492.          * to fit */
  493.  
  494.         for (ch = lochar; ch <= hichar; ch++)
  495.         {   z1 = (llx[ch] * pointsize * optxden - 41000) / 72000;
  496.             z2 = (urx[ch] * pointsize * optxden + 41000) / 72000;
  497.             if (z1 < 0) z1 = 0;
  498.             pssintf("cstr 0 %d put\n", ch);
  499.             pssintf("%d %d moveto\n", actwidth, baseline);
  500.             pssintf("gsave %d 0 rlineto 0 %d rlineto "
  501.                     "-%d 0 rlineto closepath clip\n",
  502.                     z2, -baseline, z2);
  503.             pssintf("1 setgray fill 0 setgray\n");
  504.             pssintf("%d %d moveto ", actwidth - z1, baseline);
  505.             y1 = ((-lly[ch]) * pointsize * optxden) / 72;
  506.             y2 = baseline * 1000;
  507.             if (y1 > y2)
  508.                 pssintf("1 %d %d div scale\n", y2, y1);
  509.             pssintf("cstr show\n"
  510.                     "grestore\n");
  511.             pssintf("gsave %d 0 rlineto 0 %d rlineto "
  512.                     "-%d 0 rlineto closepath clip\n",
  513.                     z2, pointsize - baseline, z2);
  514.             pssintf("1 setgray fill newpath 0 setgray\n");
  515.             pssintf("%d %d moveto ", actwidth - z1, baseline);
  516.             y1 = (ury[ch] * pointsize * optxden) / 72;
  517.             y2 = (pointsize - baseline) * 1000;
  518.             if (y1 > y2)
  519.                 pssintf("1 %d %d div scale\n", y2, y1);
  520.             pssintf("cstr show\n"
  521.                     "null currentpoint 2 { round cvi exch } repeat "
  522.                     "2 1 callextfunc\n"
  523.                     "grestore\n");
  524.             ww = cposx - actwidth;
  525.             zz = z2 - z1;
  526.             if (zz > ww) zz = ww;
  527.             i = ch - lochar;
  528.             charloc[i * 2] = actwidth;
  529.             charloc[i * 2 + 1] = zz;
  530.             charspace[i] = ww;
  531.             charkern[i] = z1;
  532.             actwidth += zz;
  533.             if (lly[ch] != ury[ch])
  534.             {   nomwidth += z1 + ww;
  535.                 nomcount++;
  536.             }
  537.             if (SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
  538.                 goto broken;
  539.         }
  540.  
  541.         if (pserror != 0) goto pserror;
  542.  
  543.         /* If we have not explicitly set the nominal character width,
  544.          * calculate it as the average width of the non-null characters
  545.          * we have generated */
  546.  
  547.         if (optwidth == -1)
  548.         {   if (nomcount != 0)
  549.                 nomwidth = (nomwidth + nomcount / 2) / nomcount;
  550.         }
  551.         else
  552.             nomwidth = (optwidth * pointsize * optxden + 36000) / 72000;
  553.  
  554.         /* We now know the actual width, so we can calculate the actual
  555.          * modulo and file lengths.  Then we must reformat the bitmap to
  556.          * the new width */
  557.  
  558.         if (actwidth > maxwidth)
  559.         {   fprintf(stderr, "mkbmap: width estimate exceeded\n");
  560.             goto errorexit;
  561.         }
  562.         actmodulo = ((actwidth + 15) >> 3) & ~1;
  563.         actcharlen = actmodulo * pointsize;
  564.         hunklen = baselen + actcharlen;
  565.         if (hunklen & 2) hunklen += 2;
  566.         hunknum = hunklen >> 2;
  567.         actfontlen = hunklen + 76;
  568.  
  569.         i = 1;
  570.         s = chardata + maxmodulo;
  571.         t = chardata + actmodulo;
  572.         while (i < pointsize)
  573.         {   l = actmodulo;
  574.             while (l--) *t++ = *s++;
  575.             i++;
  576.             s += (maxmodulo - actmodulo);
  577.         }
  578.  
  579.         /* Finish the bitmapped font.  Write it out to the file */
  580.  
  581.         buildfdirname(namebuf, argbmapfile, 2);
  582.  
  583.         hunkptr[0] = Hunk_Header;
  584.         hunkptr[1] = 0;
  585.         hunkptr[2] = 1;
  586.         hunkptr[3] = 0;
  587.         hunkptr[4] = 0;
  588.         hunkptr[5] = hunknum;
  589.         hunkptr[6] = Hunk_Code;
  590.         hunkptr[7] = hunknum;
  591.         hunkptr += 8;
  592.  
  593.         hunkptr[0] = MOVFFD0RTS;
  594.  
  595.         dfheader->dfh_DF.ln_Type = NT_FONT;
  596.         dfheader->dfh_DF.ln_Name = (char *) 0x0000001A;
  597.         dfheader->dfh_FileID = DFH_ID;
  598.         strncpy((char *)&dfheader->dfh_Name, namebuf, MAXFONTNAME);
  599.         dfheader->dfh_TF.tf_Message.mn_Node.ln_Type = NT_FONT;
  600.         dfheader->dfh_TF.tf_Message.mn_Node.ln_Name = (char *) 0x0000001A;
  601.         dfheader->dfh_TF.tf_Message.mn_Length = hunklen - 58;
  602.         dfheader->dfh_TF.tf_YSize = pointsize;
  603.         dfheader->dfh_TF.tf_Style =
  604.             (optbold ? FSF_BOLD : 0) | (optitalic ? FSF_ITALIC : 0);
  605.         dfheader->dfh_TF.tf_Flags =
  606.             (optmonospaced ? 0 : FPF_PROPORTIONAL) | FPF_DESIGNED;
  607.         dfheader->dfh_TF.tf_XSize = nomwidth;
  608.         dfheader->dfh_TF.tf_Baseline = pointsize - baseline - 1;
  609.         dfheader->dfh_TF.tf_BoldSmear = pointsize / 20 + 1;
  610.         dfheader->dfh_TF.tf_LoChar = lochar;
  611.         dfheader->dfh_TF.tf_HiChar = hichar;
  612.         dfheader->dfh_TF.tf_CharData =
  613.             (APTR) ((char *) chardata  - (char *) hunkptr);
  614.         dfheader->dfh_TF.tf_Modulo = actmodulo;
  615.         dfheader->dfh_TF.tf_CharLoc =
  616.             (APTR) ((char *) charloc   - (char *) hunkptr);
  617.         dfheader->dfh_TF.tf_CharSpace =
  618.             (APTR) ((char *) charspace - (char *) hunkptr);
  619.         dfheader->dfh_TF.tf_CharKern =
  620.             (APTR) ((char *) charkern  - (char *) hunkptr);
  621.  
  622.         hunkptr += hunknum;
  623.  
  624.         hunkptr[0] = Hunk_Reloc32;
  625.         hunkptr[1] = 6;
  626.         hunkptr[2] = 0;
  627.         hunkptr[3] = 0x0000006A;
  628.         hunkptr[4] = 0x00000066;
  629.         hunkptr[5] = 0x00000062;
  630.         hunkptr[6] = 0x0000005C;
  631.         hunkptr[7] = 0x00000044;
  632.         hunkptr[8] = 0x0000000E;
  633.         hunkptr[9] = 0;
  634.         hunkptr[10] = Hunk_End;
  635.  
  636.         pstrace("%% Writing bmap file\n");
  637.         if (buildfnumname(namebuf, argbmapfile, pointsize) == NULL)
  638.         {   fprintf(stderr, "mkbmap: bmap file name too long\n");
  639.             goto errorexit;
  640.         }
  641.         newfh = Open(namebuf, MODE_NEWFILE);
  642.         if (newfh == NULL)
  643.         {   fprintf(stderr, "mkbmap: can't open bmap file %s\n", namebuf);
  644.             goto errorexit;
  645.         }
  646.         i = Write(newfh, (UBYTE *) fontmem, actfontlen);
  647.         Close(newfh);
  648.         if (i == -1)
  649.         {   fprintf(stderr, "mkbmap: error writing bmap file %s\n", namebuf);
  650.             goto errorexit;
  651.         }
  652.     }
  653.  
  654.     /* Update font contents file */
  655.  
  656. newfont:
  657.     if (optnew)
  658.     {   pstrace("%% Updating font contents file\n");
  659.         buildfdirname(namebuf, argbmapfile, 1);
  660.         fdlock = Lock(namebuf, SHARED_LOCK);
  661.         if (fdlock == NULL)
  662.         {   fprintf(stderr, "mkbmap: can't lock font directory %s\n",
  663.                             namebuf);
  664.             goto errorexit;
  665.         }
  666.         buildfdirname(namebuf, argbmapfile, 2);
  667.         strcat(namebuf, ".font");
  668.         DiskfontBase = OpenLibrary("diskfont.library", 34);
  669.         if (DiskfontBase) fcheader = NewFontContents(fdlock, namebuf);
  670.         if (fcheader == NULL)
  671.         {   fprintf(stderr, "mkbmap: can't create new font contents %s\n",
  672.                     namebuf);
  673.             goto errorexit;
  674.         }
  675.         if (fcheader->fch_NumEntries == 0)
  676.         {   fprintf(stderr, "mkbmap: font %s directory contains no fonts\n",
  677.                     namebuf);
  678.             retcode = 10;
  679.             goto tidyexit;
  680.         }
  681.  
  682.         /* Swap to the font directory, update the file, and swap back */
  683.  
  684.         cdlock = CurrentDir(fdlock);
  685.         newfh = Open(namebuf, MODE_NEWFILE);
  686.         if (newfh)
  687.         {   i = Write(newfh, (UBYTE *)fcheader,
  688.                     sizeof (struct FontContentsHeader) +
  689.                     sizeof (struct FontContents) * fcheader->fch_NumEntries);
  690.             Close(newfh);
  691.         }
  692.         CurrentDir(cdlock);
  693.         if      (newfh == NULL)
  694.         {   fprintf(stderr, "mkbmap: can't open font contents file %s\n",
  695.                     namebuf);
  696.             goto errorexit;
  697.         }
  698.         else if (i == -1)
  699.         {   fprintf(stderr, "mkbmap: error writing font contents file %s\n",
  700.                     namebuf);
  701.             goto errorexit;
  702.         }
  703.  
  704.         /* Tidy up */
  705.  
  706.         DisposeFontContents(fcheader);
  707.         fcheader = NULL;
  708.         CloseLibrary(DiskfontBase);
  709.         DiskfontBase = NULL;
  710.         UnLock(fdlock);
  711.         fdlock = NULL;
  712.     }
  713.  
  714.     /* All done */
  715.  
  716.     pstrace("%% All done\n");
  717.     goto tidyexit;
  718.  
  719.     /* Argument errors and usage query */
  720.  
  721. query:
  722.     fprintf(stderr, "Bitmap font generator.  MkBmap version 1.0\n"
  723.                     "Makes Amiga bitmapped fonts from PostScript fonts\n"
  724.                     "\n"
  725.                     "  Usage:\n"
  726.                     "\n"
  727.                     "    mkbmap -options bmapfile fontname nn,nn,...\n"
  728.                     "\n"
  729.                     "      -s startupfile  Startup file name\n"
  730.                     "      -e encodingfile Encoding file name\n"
  731.                     "      -f              Font specific encoding\n"
  732.                     "      -n              Make new .font contents\n");
  733.     fprintf(stderr, "      -dnnn           Density: x and y (dpi)\n"
  734.                     "      -xnnn           Density: x (dpi)\n"
  735.                     "      -ynnn           Density: y (dpi)\n"
  736.                     "      -znnn           Baseline (1/1000)\n"
  737.                     "      -wnnn           Width    (1/1000)\n"
  738.                     "      -lnnn           LoChar\n"
  739.                     "      -hnnn           Hichar\n"
  740.                     "      -m              Monospaced\n"
  741.                     "      -b              Bold\n"
  742.                     "      -i              Italic\n"
  743.                     "      -t              Trace (for debuggindg)\n"
  744.                     "\n"
  745.                     "  For example:\n"
  746.                     "\n"
  747.                     "    mkbmap -n fonts:Times/* Times-Roman 10,12,14\n");
  748.     goto tidyexit;
  749.  
  750. badargs:
  751.     fprintf(stderr, "mkbmap: arguments bad, or value missing");
  752. badusage:
  753.     retcode = 20;
  754.     fprintf(stderr, ".  Usage:\n"
  755.                     "    mkbmap -options bmapfile fontname nn,nn,...\n");
  756.     goto tidyexit;
  757.  
  758.     /* PostScript library error */
  759.  
  760. pserror:
  761.     fprintf(stderr, "mkbmap: post.library interpreter error\n");
  762.     goto errorexit;
  763.  
  764.     /* Tidy up and exit */
  765.  
  766. broken:
  767.     fprintf(stderr, "mkbmap: *** Break\n");
  768.     retcode = 10;
  769.     goto tidyexit;
  770.  
  771. errorexit:
  772.     retcode = 20;
  773.  
  774. tidyexit:
  775.     if (ftrapset)
  776.     {   deleteftrap();
  777.         ftrapset = 0;
  778.     }
  779.  
  780.     if (arec) PSdeleteact(arec);
  781.     if (PSbase) CloseLibrary(PSbase);
  782.  
  783.     if (fontmem) FreeMem(fontmem, maxfontlen);
  784.  
  785.     if (fcheader) DisposeFontContents(fcheader);
  786.     if (DiskfontBase) CloseLibrary(DiskfontBase);
  787.     if (fdlock) UnLock(fdlock);
  788.  
  789.     exit(retcode);
  790. }
  791.  
  792. /* String to integer conversion; digits only, with error check */
  793.  
  794. int strtoint(char **sp, int *ip)
  795. {   char *s = *sp;
  796.     int i = 0;
  797.     int ch;
  798.     for (;;)
  799.     {   ch = *s;
  800.         if (ch < '0' || ch > '9') break;
  801.         i = i * 10 + (ch - '0');
  802.         s++;
  803.     }
  804.     if (s == *sp)
  805.         return 0;
  806.     else
  807.     {   *sp = s;
  808.         *ip = i;
  809.         return 1;
  810.     }
  811. }
  812.  
  813. /* Build the bitmap font file name.  Copy it, replacing "*" by the point
  814.  * size.  Then scan it backwards replacing "?" by digits */
  815.  
  816. char *buildfnumname(char *nbuf, char *name, int num)
  817. {   char number[10];
  818.     int numlen, i, j, k, ch;
  819.     numlen = 0;
  820.     while (num)
  821.     {   number[numlen++] = num % 10 + '0';
  822.         num /= 10;
  823.     }
  824.     i = j = 0;
  825.     for (;;)
  826.     {   if (j > 100) return NULL;
  827.         ch = name[i++];
  828.         if (ch == '*')
  829.         {   k = numlen;
  830.             while (k--) nbuf[j++] = number[k];
  831.         }
  832.         else
  833.            nbuf[j++] = ch;
  834.         if (ch == 0) break;
  835.     }
  836.     k = 0;
  837.     while (--j)
  838.     {   if (nbuf[j] == '?')
  839.             nbuf[j] = (k < numlen) ? number[k++] : '0';
  840.     }
  841.     return nbuf;
  842. }
  843.  
  844. /* Build the font file/directory name.  We copy it, striping off the last
  845.  * two components:
  846.  *
  847.  * type = 0: fontdir/fontname/* => fontdir/fontname
  848.  * type = 1: fontdir/fontname/* => fontdir
  849.  * type = 2: fontdir/fontname/* => fontname
  850.  *
  851.  *       (or fontdir:fontname/* => ...)
  852.  */
  853.  
  854. char *buildfdirname(char *nbuf, char *name, int type)
  855. {   int i, j, k;
  856.     i = strlen(name);
  857.     for (;;)
  858.     {   if (i == 0) return NULL;
  859.         i--;
  860.         if (name[i] == ':') return NULL;
  861.         if (name[i] == '/') break;
  862.     }
  863.     j = i;
  864.     for (;;)
  865.     {   if (j == 0) return NULL;
  866.         j--;
  867.         if (name[j] == ':')
  868.         {   k = j = j + 1;
  869.             break;
  870.         }
  871.         if (name[j] == '/')
  872.         {   k = j;
  873.             j = j + 1;
  874.             break;
  875.         }
  876.     }
  877.     if (k == 0) return NULL;
  878.     if (i >= 100) return NULL;
  879.     if      (type == 1)
  880.         i = k;
  881.     else if (type == 2)
  882.     {   name += j;
  883.         i -= j;
  884.     }
  885.     memcpy(nbuf, name, i);
  886.     nbuf[i] = 0;
  887.     return nbuf;
  888. }
  889.  
  890. /* Trace output */
  891.  
  892. void pstrace(char *format, ...)
  893. {   va_list ap;
  894.     if (pserror != 0) return;
  895.     if (opttrace)
  896.     {   va_start(ap, format);
  897.         vfprintf(stdout, format, ap);
  898.         fflush(stdout);
  899.         va_end(ap);
  900.     }
  901. }
  902.  
  903. /* Interpret postscript string */
  904.  
  905. void pssintf(char *format, ...)
  906. {   va_list ap;
  907.     if (pserror != 0) return;
  908.     va_start(ap, format);
  909.     if (opttrace)
  910.     {   vfprintf(stdout, format, ap);
  911.         fflush(stdout);
  912.     }
  913.     vsprintf(psstring, format, ap);
  914.     pserror = PSintstring(arec, psstring, -1, PSFLAGSTRING)
  915.     va_end(ap);
  916. }
  917.  
  918. /* Set character bounding box */
  919.  
  920. void __saveds setbbox(int ch, int lx, int ly, int rx, int uy)
  921. {   llx[ch] = lx;
  922.     lly[ch] = ly;
  923.     urx[ch] = rx;
  924.     ury[ch] = uy;
  925. }
  926.  
  927. /* Set current point */
  928.  
  929. void __saveds setcpos(int cpx, int cpy)
  930. {   cposx = cpx;
  931.     cposy = cpy;
  932. }
  933.  
  934. /* Signal an interrupt */
  935.  
  936. void __saveds sigint()
  937. {   PSsignalint(arec, 1);
  938. }
  939.  
  940. /* Signal a floating point error */
  941.  
  942. void __saveds sigfpe()
  943. {   PSsignalfpe(arec);
  944. }
  945.  
  946. /* Dummy stub routine */
  947.  
  948. void stub(void)
  949. {   return;
  950. }
  951.  
  952. /* Dummy check abort routine */
  953.  
  954. void chkabort(void)
  955. {   return;
  956. }
  957.  
  958. /* End of file "mkbmap.c" */
  959.